#include "console-common.h"
#include "lua-attrib.h"
#include "lua-conwin-const.h"
#define ATTR_ARGS 2
#define ATTR_FUNC(x) __luacon_attrib_##x
#define STATICFN(x, L) static int ATTR_FUNC(x) (lua_State * L)

static void __console_push_attr (int n)
{
	int top = attr_stack[0];
	attr_stack[0] += ATTR_ARGS + n;
	if ((top + ATTR_ARGS) > attr_stack[1])
	{
		attr_stack[1] *= 2;
		attr_stack.resize(attr_stack[1]);
	}
	attr_stack[top+n] = curr_fg;
	attr_stack[top+n+1] = curr_bg;
}

static void __move_attr_from_stack (int n)
{
	curr_fg = attr_stack[n],
	curr_bg = attr_stack[n+1];
}

STATICFN(push, L)
{
	int args = lua_gettop(L);
	__console_push_attr (0);
	if (args >= 1) curr_fg = luaL_checkint(L, 1);
	if (args >= 2) curr_bg = luaL_checkint(L, 2);
	return 0;
}

STATICFN(pushswap, L)
{
	__console_push_attr (0);
	swap_int(curr_fg, curr_bg);
	return 0;
}

STATICFN(pop, L)
{
	int pops = luaL_optint(L, 1, 1);
	if (pops <= 0) return 0;

	int top = attr_stack[0], b = 0;
	top -= pops * ATTR_ARGS;

	if (top < ATTR_STACK_BASE)
		top = ATTR_STACK_BASE, b = -ATTR_ARGS;

	__move_attr_from_stack(top+b);
	attr_stack[0] = top;
	return 0;
}

STATICFN(set, L)
{
	int args = lua_gettop(L);
	if (args >= 1)
	{
		if (args >= 2) curr_bg = luaL_checkinteger(L, 2);
		curr_fg = luaL_checkinteger(L, 1);
		return 0;
	}
	lua_pushinteger(L, curr_fg);
	lua_pushinteger(L, curr_bg);
	return 2;
}

STATICFN(reset, L)
{
	int flags = luaL_optint(L, 1, 0), top;

	if (flags & FLAG_RESET_STACK)
		attr_stack[0] = top = ATTR_STACK_BASE;
	else
		top = attr_stack[0];
	
	__move_attr_from_stack(top-ATTR_ARGS);
	return 0;
}

STATICFN(swap, L)
{
	swap_int(curr_fg, curr_bg);
	return 0;
}

STATICFN(gettop, L)
{
	lua_pushinteger(L, (attr_stack[0] - ATTR_STACK_BASE) / ATTR_ARGS);
	return 1;
}

STATICFN(settop, L)
{
	int tmp = ATTR_STACK_BASE + luaL_checkinteger(L, 1) * ATTR_ARGS;
	bool set_attr = lua_toboolean(L, 2);
	if (tmp < attr_stack[0]) { attr_stack[0] = tmp; if (set_attr) __move_attr_from_stack(attr_stack[0]); }
	return 0;
}

void luaopen_con_attribute_api_ (lua_State * L)
{
#define ARGEXT0(x) {#x,ATTR_FUNC(x)},
	const static struct luaL_Reg table1 [] = {
		ARGEXT0(push) ARGEXT0(pushswap) ARGEXT0(pop) ARGEXT0(set) ARGEXT0(reset) ARGEXT0(swap) ARGEXT0(gettop) ARGEXT0(settop)
		{NULL, NULL},
	};
#undef ARGEXT0
	lua_newtable(L);
	luaL_set_cfuncs(L, table1);
	lua_setfield(L, -2, "attribute");
}